#pragma once
#include <iostream>
#include <cstring>
#include <string>
#include <cerrno>
#include <sys/types.h>  // ::socket
#include <sys/socket.h>
#include <netinet/in.h> // ::bind
#include <arpa/inet.h>
#include <unistd.h>

#include "Log.hpp"
#include "Common.hpp"

#define BACKLOG 8

using namespace LogMudule;

static const uint16_t gport = 8080;

class Tcpserver
{
public:
    Tcpserver(uint16_t port = gport)
        : _port(port)
        , _isrunning(false)
    {}
    // 初始化TCP服务器
    void InitServer()
    {
        // 1. 创建tcp socket
        //                 默认网络编程，   流式套接字
        _listensockfd = ::socket(AF_INET, SOCK_STREAM, 0);
        if(_listensockfd < 0)
        {
            LOG(LogLevel::FATAL) << "socket error";
            Die(SOCKET_ERR);
        }
        LOG(LogLevel::INFO) << "socket create success, sockfd is : " << _listensockfd;

        // 2. bind
        struct sockaddr_in local;
        memset(&local, 0, sizeof(local));
        // 填充字段
        local.sin_family = AF_INET;
        local.sin_port = htons(gport);  // 需要经过网络发送给对端，所以将端口号转为网络序列
        local.sin_addr.s_addr = INADDR_ANY; // 绑定任意ip
        
        int n = ::bind(_listensockfd, CONV(&local), sizeof(local));
        if(n < 0)
        {
            LOG(LogLevel::FATAL) << "bind error";
            Die(BIND_ERR);
        }
        LOG(LogLevel::INFO) << "bind success, sockfd is : " << _listensockfd;

        // 3. client -> server, tcp是面向连接的，就要求tcp服务器随时随地等待被连接
        // tcp 需要将socket设置成为监听状态，即随时等待别人来链接我。tcp 特有的
        n = ::listen(_listensockfd, BACKLOG); // 设置监听状态
        if(n < 0)
        {
            LOG(LogLevel::FATAL) << "listen error";
            Die(LISTEN_ERR);
        }
        LOG(LogLevel::INFO) << "listen success, sockfd is : " << _listensockfd;
    }

    void HandlerRequest(int sockfd)
    {
        while(true)
        {
            // 从网络中读取数据，读取到inbuffer中
            char inbuffer[4096];
            ssize_t n = ::read(sockfd, inbuffer, sizeof(inbuffer) - 1);
            if(n > 0)   // 读成功
            {
                // 服务器显示的消息
                LOG(LogLevel::INFO) << inbuffer;
                inbuffer[n] = 0;
                std::string echo_str = "server echo# ";
                echo_str += inbuffer;
                // 客户端发送的消息，服务器会进行回显，回显在客户端
                ::write(sockfd, echo_str.c_str(), echo_str.size());
            }
        }
    }
    // 启动TCP服务器
    void Start()
    {
        _isrunning = true;
        while(_isrunning)
        {
            // TCP不能直接读取数据
            // 1. 获取新连接
            struct sockaddr_in peer;
            socklen_t peerlen = sizeof(peer);
            int sockfd = ::accept(_listensockfd, CONV(&peer), &peerlen);     // 重点
            if(sockfd < 0)
            {
                LOG(LogLevel::WARNING) << "accept error: " << strerror(errno);
                continue;
            }

            // 走到这里说明获取连接成功了
            LOG(LogLevel::INFO) << "accept success, sockfd is : " << sockfd;
            // InetAddr addr(peer);
            // LOG(LogLevel::INFO) << "client info: " << addr.Addr();

            // version 0
            // 处理请求
            HandlerRequest(sockfd);
        }
    }
    // 关闭TCP服务器
    void Stop()
    {
        _isrunning = false;
    }
    ~Tcpserver()
    {}
private:
    int _listensockfd;  // 监听socket
    uint16_t _port;
    bool _isrunning;    // TCP服务器状态
};